package com.example.smalltool.utils;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.Map;
import java.util.UUID;

/**
 * spring容器中获取bean对象的工具
 背景说明：
	用spring来管理各个实例(bean), 有时在程序中为了使用已被实例化的bean, 读取“applicationContext-common.xml”中的内容：
		ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext-common.xml");  
		AbcService abcService = (AbcService)appContext.getBean("abcService");  
	但是这样就会存在一个问题：因为它会重新装载applicationContext-common.xml并实例化上下文bean，
	如果有些线程配置类也是在这个配置文件中，那么会造成做相同工作的的线程会被启两次。
	一次是web容器初始化时启动，另一次是上述代码显示的实例化了一次。当于重新初始化一遍！！！！这样就产生了冗余

	解决上面问题的办法：实现ApplicationContextAware接口
 */
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        if (null == ApplicationContextUtil.applicationContext){
            ApplicationContextUtil.applicationContext = context;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 根据bean的id来查找对象
     */
    public static Object getBean(String beanName) {
        if (null == applicationContext) {
            return null;
        }
        return applicationContext.getBean(beanName);
    }

    /**
     * 根据bean的class来查找对象
     */
    public static <T> T getBean(Class<T> clazz) {
        if (null == applicationContext) {
            return null;
        }
        return applicationContext.getBean(clazz);
    }

    /**
     * 根据bean的class来查找对象
     */
    public static <T> T getBean(String beanName, Class<T> clazz) {
        if (null == applicationContext) {
            return null;
        }
        return applicationContext.getBean(beanName, clazz);
    }

    /**
     * 根据bean的class来查找所有的对象(包括子类)
     *
     * @param clazz
     * @return
     */
    public static <T> Map<String, T> getBeans(Class<T> clazz) {
        if (null == applicationContext) {
            return null;
        }
        return applicationContext.getBeansOfType(clazz);
    }

    /**
     * 根据bean的class获取实例对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getInstanceBean(Class<T> clazz) {
        if (null == applicationContext) {
            return null;
        }
        T _t = null;
        try {
            String beanName = clazz.getSimpleName() + UUID.randomUUID();
            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            beanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition());
            _t = applicationContext.getBean(beanName, clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return _t;
    }

}
